package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.OrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Service
@Slf4j
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    AttendGroupMapper attendGroupMapper;

    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    @Autowired
    OrganizationFeign organizationFeign;

    /**
     * 1. 判断企业是否初次使用（该企业是否关联考勤组）
     * 2. 如果企业初次使用，初始化默认考勤组
     * 3. 分页查询考勤组列表
     * 4. 统计每个考勤组关联的人数， 组装，并返回
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {
        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Integer count = attendGroupMapper.selectCount(attendGroupQw);
        if(count == 0){
            //企业初次使用， 初始化默认考勤组
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            //默认考勤要关联我们所有的员工(所有的顶级部门)
            //查询所有的顶级部门
            List<Long> departmentIds = organizationFeign.queryDepartmentIds().getData();
            //考勤组 与部门关联
            if(CollectionUtil.isNotEmpty(departmentIds)){
                for (Long departmentId : departmentIds) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                    attendGroupPart.setObjectType(1); // 部门或者 用户 的类型
                    attendGroupPart.setObjectId(departmentId); //部门或者用户 的id
                    attendGroupPart.setAttendType(1); //是否参加考勤

                    attendGroupPartMapper.insert(attendGroupPart);
                }
            }


        }

        //分页查询
        Page<AttendGroup> attendGroupPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<AttendGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        attendGroupMapper.selectPage(attendGroupPage, wrapper);

        //考勤组列表数据
        List<AttendGroup> records = attendGroupPage.getRecords();
        List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);

        //循环每一个考勤组
        for (AttendGroupDTO attendGroupDTO : attendGroupDTOS) {
            //把考勤组 关联的 关系数据查询出来
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());

            List<AttendGroupPart> attendGroupPartList = attendGroupPartMapper.selectList(attendGroupPartQw);
            //分类：把部门和 员工的关系分开
            List<Long> departmentIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                //部门类型
                return attendGroupPart.getObjectType() == 1;
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            //统计部门对应的员工数量
            // 统计每个考勤组 关联的员工数量
            Integer departmentCount = organizationFeign.queryUserCountByDepartmentIds(departmentIds).getData();

            List<Long> userIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                //员工类型
                return attendGroupPart.getObjectType() == 2;
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());


            attendGroupDTO.setMemberNum(departmentCount + (userIds == null ? 0: userIds.size()));
        }

        PageResult<AttendGroupDTO> pageResult = new PageResult<>();
        pageResult.setTotal(attendGroupPage.getTotal());
        pageResult.setTotalPage(attendGroupPage.getPages());
        pageResult.setRows(attendGroupDTOS);

        return pageResult;
    }

    @Override
    public void add(AttendGroupDTO attendGroupDTO) {
        if( attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //把dto 复制为  pojo
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        //设置基础信息
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setCreateTime(new Date());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        //设置工作日
        List<String> workdays = attendGroupDTO.getWorkdays();
        String join = StrUtil.join(",", workdays);
        attendGroup.setWorkdays(join);

        //特殊日期的处理
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        //获取无需打卡的时间列表
        List<String> unnecessaryTimeList = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 0;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());

        //获取 需要打卡的时间列表
        List<String> necessaryTimeList = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 1;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());

        //无需打卡的时间列表
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",", unnecessaryTimeList));
        //需要打卡时间列表
        attendGroup.setNecessaryTimeList(StrUtil.join(",", necessaryTimeList));

        //新增考勤组
        attendGroupMapper.insert(attendGroup);


        // 管理考勤组和 部门、员工之间的关系
        //需要考勤的人员
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();

        if(CollectionUtil.isNotEmpty(participates)){
            for (AttendGroupPartDTO participate : participates) {
                //删除 部门/员工 与其他考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId());

                attendGroupPartMapper.delete(attendGroupPartQw);

                //维护 部门/员工 与新考勤组的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                attendGroupPart.setAttendType(1); //考勤类型（无需考勤，需要考勤）
                attendGroupPart.setObjectType(participate.getObjectType()); // 考勤对象的类型（部门/员工）
                attendGroupPart.setObjectId(participate.getObjectId()); //部门id 或者员工id

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }


        //无需考勤的人员
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();

        if(CollectionUtil.isNotEmpty(notParticipates)){
            for (AttendGroupPartDTO participate : notParticipates) {
                //删除 部门/员工 与其他考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId());

                attendGroupPartMapper.delete(attendGroupPartQw);

                //维护 部门/员工 与新考勤组的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                attendGroupPart.setAttendType(2); //考勤类型（无需考勤，需要考勤）
                attendGroupPart.setObjectType(participate.getObjectType()); // 考勤对象的类型（部门/员工）
                attendGroupPart.setObjectId(participate.getObjectId()); //部门id 或者员工id

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }
    }

    /**
     * 根据员工id查询所在考勤组
     * 1. 查询员工id（线程中）
     * 2. 根据员工id 查询 与考勤组的关系， 如果能查询到，直接返回， 如果没有，查询部门与考勤组的关系
     * 3. 先查询员工所在的部门id集合， 再根据部门id 查询所在的考勤组
     * @return
     */
    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //从线程中获取员工id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //获取员工与考勤组的关系
        LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroupPart::getObjectType, 2);
        wrapper.eq(AttendGroupPart::getObjectId, companyUserId);
        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(wrapper);
        //如果没有查询到员工与考勤组的关系， 根据部门id查询与考勤组的关系
        if(attendGroupPart == null){
            //获取员工 所在的部门以及上级部门id
            List<Long> ids = organizationFeign.queryDepartmentsByUserId(companyUserId).getData();
            if(ids != null){
                for (Long departmentId : ids) {
                    wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(AttendGroupPart::getObjectType, 1);
                    wrapper.eq(AttendGroupPart::getObjectId, departmentId);
                    attendGroupPart = attendGroupPartMapper.selectOne(wrapper);
                    if(attendGroupPart != null){
                        break;
                    }
                }
            }
        }

        if( attendGroupPart == null){
            throw new NcException(ResponseEnum.USER_NOT_MATCH_ATTENDGROUP);
        }

        Long attendGroupId = attendGroupPart.getAttendGroupId();
        AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
        AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
        String workdays = attendGroup.getWorkdays(); //1,1,1,1,0,0,0
        String[] split = workdays.split(",");
        attendGroupDTO.setWorkdays(Arrays.asList(split));
        return attendGroupDTO;
    }

    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(30);
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setOffWorkTime("17:00:00");
        attendGroup.setWorkdays("[1,1,1,1,1,0,0]");
        attendGroup.setAddress("山东省济南市普利商务中心");
        attendGroup.setAddressName("济南校区");
        attendGroup.setLat(117.081293);
        attendGroup.setLng(36.671775);
        attendGroup.setAddressRange(1000);
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        return attendGroup;
    }
}
